package com.ruoyi.web.controller.fenxi.utils;


import com.ruoyi.common.config.ServerConfig;
import com.ruoyi.common.utils.HttpContextUtils;
import com.ruoyi.common.utils.PropertiesUtils;
import com.ruoyi.common.utils.SpringContextUtils;
import com.ruoyi.system.domain.RDataDetail;
import com.ruoyi.system.domain.RModel;
import com.ruoyi.system.service.IRDataDetailService;
import com.ruoyi.system.service.IRModelService;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class ImportUtil implements Runnable  {
    private Map<String, QueueModel> donwMap = new LinkedHashMap<>();
    private Map<String, QueueModel> queueMap = new LinkedHashMap<>();
    private static final ImportUtil INSTANCE = new ImportUtil();
    private Thread importThread;

    private ImportUtil() {
        this.importThread = new Thread(this, "importMoneyThread");
        this.importThread.setPriority(2);
        this.importThread.start();
    }

    public static ImportUtil getInstance() {
        return INSTANCE;
    }

    public QueueModel getQueueModel(String code) {
        QueueModel ret = queueMap.get(code);
        if (ret == null) {
            ret = donwMap.get(code);
        }
        return ret;
    }

    public void import2DB(Long id, Long userId, String path, String conda_path, String startName, String code) {
        QueueModel queueModel = new QueueModel();
        queueModel.setCurStatus(QueueModel.STATUS_ANALYSIS_UNZIP_START);
        queueModel.setUserId(userId);
        queueModel.setPath(path);
        queueModel.setId(id);
        queueModel.setCondaPath(conda_path);
        queueModel.setCode(code);
        queueModel.setStartName(startName);
        queueMap.put(code, queueModel);
    }

    public void import2Data(Long id, Long userId, String path, String code) {
        QueueModel queueModel = new QueueModel();
        queueModel.setCurStatus(QueueModel.STATUS_ANALYSIS_UNZIP_START);
        queueModel.setId(id);
        queueModel.setUserId(userId);
        queueModel.setPath(path);
        queueModel.setCode(code);
        queueMap.put(code, queueModel);
    }

    public void run() {
        while (true) {
            try {
                if (queueMap.isEmpty()) {
                    Thread.sleep(3000);
                } else {
                    Map.Entry<String, QueueModel> entry = queueMap.entrySet().iterator().next();
                    QueueModel queueModel = entry.getValue();
                    String code = entry.getKey();
                    queueModel.setCurStatus(QueueModel.STATUS_ANALYSIS_UNZIP_START);
                    if (code.startsWith("model")) {
                        save2RModel(code);
                    } else if (code.startsWith("data")){
                        save2RData(code);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 解压缩zip文件并根据工程名创建conda环境
     * @return
     */
    private void save2RModel(String code) {
        String root = PropertiesUtils.getInstance().get("file_path");

        IRModelService service = (IRModelService) SpringContextUtils.getBean(IRModelService.class);
        QueueModel queueModel = queueMap.get(code);

        Long id = queueModel.getId();
        String path = queueModel.getPath();
        String conda_path = queueModel.getCondaPath();
        String startName = queueModel.getStartName();

        String fileName = ZipUtil.unzip(path, root);
        queueModel.setCurStatus(queueModel.STATUS_ANALYSIS_CONDA_UNZIP_START);
        File dir = new File(PropertiesUtils.getInstance().get("conda_envs_path"));
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String condaName = ZipUtil.unzip(conda_path, PropertiesUtils.getInstance().get("conda_envs_path"));

        fileName = fileName.split("/")[0];
        condaName = condaName.split("/")[0];

        RModel model = new RModel();
        model.setId(id);
        model.setProjName(fileName);
        model.setCondaName(condaName);
        service.updateRModel(model);

        queueModel.setCurStatus(queueModel.STATUS_ANALYSIS_START_SH_START);

        StringBuffer sb = new StringBuffer();
        sb.append("#!/bin/sh");
        sb.append("\n");
        sb.append("source activate " + condaName);
        sb.append("\n");
        sb.append("cd " + root + "/" + fileName);
        sb.append("\n");
        sb.append("nohup python " + startName + " >> server.out 2>&1&");

        writeFile(sb.toString(), root + "/" + fileName + "/" + "start.sh");

        queueModel.setCurStatus(queueModel.STATUS_ANALYSIS_SHUTDOWN_SH_START);

        sb = new StringBuffer();
        sb.append("#!/bin/bash");
        sb.append("\n");
        sb.append("ENVT=$1");
        sb.append("\n");
        sb.append("TARGETS=('" + startName + "')");
        sb.append("\n");
        sb.append("for target in '${TARGETS[@]}'");
        sb.append("\n");
        sb.append("do");
        sb.append("\n");
        sb.append("    pkill -f $target");
        sb.append("\n");
        sb.append("echo 'killing process $target'");
        sb.append("\n");
        sb.append("done");

        writeFile(sb.toString(), root + "/" + fileName + "/" + "shutdown.sh");


//        String python = queueModel.getPythonVersion();
//        String file_name = queueModel.getFileName();
//
//        String cmd = "conda create -n " + file_name.replace(".zip", "") + " python=" + python.replace("python", "") + " -y";
//        CmdUtils.processCMD(cmd);
//        queueModel.setCurStatus(queueModel.STATUS_ANALYSIS_PIP_START);
//
//        cmd = "conda init bash && conda.bat activate " + file_name.replace(".zip", "") + " && conda.bat install --yes --file " + PropertiesUtils.getInstance().get("file_path") + file_name.replace(".zip", "") + "/requirements.txt";
//        CmdUtils.processCMD(cmd);

        queueModel.setCurStatus(QueueModel.STATUS_ALL_END);
        queueModel = queueMap.remove(code);
        donwMap.put(code, queueModel);
    }

    private void save2RData(String code) {
        int buffer = 1024;

        QueueModel queueModel = queueMap.get(code);
        Long parentId = queueModel.getId();
        String path = queueModel.getPath();

        String root = PropertiesUtils.getInstance().get("data_path") + parentId + "/";

        try {
            File rootDir = new File(root);
            rootDir.mkdirs();
            BufferedOutputStream dest = null;
            BufferedInputStream is = null;

            ZipEntry entry;
            ZipFile zipfile = new ZipFile(path, Charset.forName("GBK"));

            queueModel.setTotal(zipfile.size()-1);
            queueModel.setCurrent(0);
            Enumeration e = zipfile.entries();
            while (e.hasMoreElements()) {
                entry = (ZipEntry) e.nextElement();
                if( entry.isDirectory()){
                    continue;
                }else{
                    is = new BufferedInputStream(zipfile.getInputStream(entry));
                    int count;
                    byte[] dataByte = new byte[buffer];
                    String name = entry.getName();
                    String[] names = name.split("/");
                    name = names[names.length-1];
                    FileOutputStream fos = new FileOutputStream(root+name);
                    dest = new BufferedOutputStream(fos, buffer);
                    while ((count = is.read(dataByte, 0, buffer)) != -1) {
                        dest.write(dataByte, 0, count);
                    }
                    dest.flush();
                    dest.close();
                    is.close();
                    IRDataDetailService service = (IRDataDetailService) SpringContextUtils.getBean(IRDataDetailService.class);
                    RDataDetail model = new RDataDetail();
                    model.setParentId(parentId);
                    String modelName = "/"+root.replaceAll(PropertiesUtils.getInstance().get("file_path"),"")+name;
                    String url = PropertiesUtils.getInstance().get("data_detail_url") + modelName;
                    model.setName(url);
                    service.insertRDataDetail(model);
                    queueModel.setCurrent(queueModel.getCurrent()+1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        queueModel.setCurStatus(QueueModel.STATUS_ALL_END);
        queueModel = queueMap.remove(code);
        donwMap.put(code, queueModel);
    }

    private static void writeFile(String content, String filePath) {
        try {
            FileWriter fw = new FileWriter(filePath, true);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(content);// 往已有的文件上添加字符串
            bw.close();
            fw.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
